package com.novoda.runbuddy.provider;

import java.util.HashMap;
import java.util.Map;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

public class CheckPointsProvider extends IRBContentProvider {

	private static final String			CHECKPOINT_LOCATION_JOIN		= "checkPoint LEFT OUTER JOIN geoLocation ON (checkPoint._idGeolocation = geoLocation._id)";
	private static Map<String, String>	CHECKPOINT_LIST_PROJECTION_MAP	= null;

	public CheckPointsProvider(ContentProvider cp, SQLiteOpenHelper mOpenHelper) {
		super(cp, mOpenHelper);
	}

	@Override
	public String getType(Uri uri) {
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		int match = URI_MATCHER.match(uri);
		switch (match) {
			case CHECKPOINTS:
				return insertCheckPoint(values);
			default:
				throw new IllegalArgumentException("Unknown URL " + uri);
		}
	}

	private Uri insertCheckPoint(ContentValues initialValues) {
		long rowID;
		ContentValues values;
		if (initialValues != null) {
			values = new ContentValues(initialValues);
		} else {
			values = new ContentValues();
		}
		Long now = Long.valueOf(System.currentTimeMillis());
		Resources r = Resources.getSystem();

		if (values.containsKey(RunBuddyCP.CheckPoints.NAME) == false) {
			values.put(RunBuddyCP.CheckPoints.NAME, r.getString(android.R.string.untitled));
		}

		if (values.containsKey(RunBuddyCP.CheckPoints.SERVER_ID) == false) {
			values.put(RunBuddyCP.CheckPoints.SERVER_ID, 1);
		}

		if (values.containsKey(RunBuddyCP.CheckPoints.IMPLEMENTOR) == false) {
			values.put(RunBuddyCP.CheckPoints.IMPLEMENTOR, -1);
		}

		if (values.containsKey(RunBuddyCP.CheckPoints.DESCRIPTION) == false) {
			values.put(RunBuddyCP.CheckPoints.SERVER_ID, "none");
		}

		if (values.containsKey(RunBuddyCP.CheckPoints.CREATED_DATE) == false) {
			values.put(RunBuddyCP.CheckPoints.CREATED_DATE, now);
		}

		if (values.containsKey(RunBuddyCP.CheckPoints.MODIFIED_DATE) == false) {
			values.put(RunBuddyCP.CheckPoints.MODIFIED_DATE, now);
		}

		long latitude = values.getAsLong(RunBuddyCP.CheckPoints.LATITUDE);
		long longitude = values.getAsLong(RunBuddyCP.CheckPoints.LONGITUDE);
		long altitude = values.getAsLong(RunBuddyCP.CheckPoints.ALTITUDE);

		long geoLocationId = insertGeoLocation(latitude, longitude, altitude);

		values.remove(RunBuddyCP.CheckPoints.LATITUDE);
		values.remove(RunBuddyCP.CheckPoints.LONGITUDE);
		values.remove(RunBuddyCP.CheckPoints.ALTITUDE);
		values.put("_idGeoLocation", geoLocationId);

		rowID = getWritableDatabase().insert("checkPoint", "name", values);
		if (rowID > 0) {
			getWritableDatabase().update("checkPoint", values, "_id=" + rowID, null);
			Uri uri = ContentUris.appendId(RunBuddyCP.CheckPoints.CONTENT_URI.buildUpon(), rowID).build();
			getContext().getContentResolver().notifyChange(uri, null);
			return uri;
		}
		throw new SQLException("Failed to insert row into checkpoints");
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		Cursor c = null;

		int match = URI_MATCHER.match(uri);
		switch (match) {
			case CHECKPOINTS:
				qb.setTables(CHECKPOINT_LOCATION_JOIN);
				qb.setProjectionMap(CHECKPOINT_LIST_PROJECTION_MAP);
				break;
			case CHECKPOINT_ID:
				qb.setTables(CHECKPOINT_LOCATION_JOIN);
				qb.setProjectionMap(CHECKPOINT_LIST_PROJECTION_MAP);
				qb.appendWhere("checkPoint._id=" + uri.getPathSegments().get(1));
				break;
			default:
				throw new IllegalArgumentException("Unknown URL " + uri);
		}

		c = qb.query(getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int count;
		SQLiteDatabase db = getWritableDatabase();
		switch (URI_MATCHER.match(uri)) {
			case CHECKPOINTS:
				count = db.delete("checkPoints", selection, selectionArgs);
				break;

			case CHECKPOINT_ID:
				if (!TextUtils.isEmpty(selection) || (selectionArgs != null)) {
					throw new UnsupportedOperationException("Cannot update checkPoint using where clause");
				}
				String checkPoint_id = uri.getPathSegments().get(1);
				count = db.delete("checkPoint", "_id=?", new String[] { checkPoint_id });
				break;

			default:
				throw new IllegalArgumentException("Unknown URL " + uri);
		}

		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int count;
        SQLiteDatabase db = getWritableDatabase();
        switch (URI_MATCHER.match(uri)) {
        case CHECKPOINTS:
            count = db.update("checkPoint", values, selection, selectionArgs);
            break;

        case CHECKPOINT_ID:
            values.put(RunBuddyCP.CheckPoints.MODIFIED_DATE, System.currentTimeMillis());
            count = db.update(CHECKPOINT_LOCATION_JOIN, values, selection, selectionArgs);
            break;

        default:
            throw new IllegalArgumentException("Unknown URL " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
	}

	static {
		CHECKPOINT_LIST_PROJECTION_MAP = new HashMap<String, String>();

		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.NAME, "checkpoint.name");
		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.SERVER_ID, "__id");
		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.DESCRIPTION, "description");
		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.IMPLEMENTOR, "implementor");

		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.ALTITUDE, "geoLocation.altitude");
		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.LONGITUDE, "geoLocation.longitude");
		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.LATITUDE, "geoLocation.latitude");

		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.CREATED_DATE, "createdAt");
		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.MODIFIED_DATE, "modifiedAt");

		CHECKPOINT_LIST_PROJECTION_MAP.put(RunBuddyCP.CheckPoints.DEFAULT_SORT_ORDER, "checkPoint.latitude DESC");
	}

}
